﻿using System;
using System.Collections.Generic;
using Vallejos.Entidades.Interfaces;
using Vallejos.Entidades.ModeloDeDatos;
using Vallejos.Excepciones;
using Vallejos.Mensajes;
using Vallejos.Datos.Accesos;
using System.Linq;
using System.Linq.Expressions;

namespace Vallejos.Negocio
{
    internal class SeguridadBLL : ISeguridad
    {
        private MensajesMgr _mensaje;
        private readonly SeguridadDAL _seguridad;
        private readonly ComunBLL _comun;
        private readonly HelperCache _cache;

        public SeguridadBLL ()
        {
            _seguridad = new SeguridadDAL();
            _comun = new ComunBLL();
            _cache = new HelperCache();
        }

        public Persona Autenticar(Usuario usuario, int idLenguaje)
        {
            if(String.IsNullOrEmpty(usuario.Login))
                throw new ExcepcionNegocio(_mensaje.ObtenerMensaje(MensajesPermitidos.UsuarioMandatorio), false);

            if (String.IsNullOrEmpty(usuario.Password))
                throw new ExcepcionNegocio(_mensaje.ObtenerMensaje(MensajesPermitidos.PasswordMandatorio), false);

            var persona = _seguridad.Autenticar(usuario);

            if (persona == null)//TODO: IMPLEMENTAR MENSAJE PARA USUARIO O CONTRASEñA INCORRECTA
                throw new ExcepcionNegocio("Contraseña incorrecta", false);

            if(!persona.Usuario.Activo)//TODO: IMPLEMENTAR MENSAJE PARA USUARIO INACTIVO
                throw new ExcepcionNegocio(_mensaje.ObtenerMensaje(MensajesPermitidos.PasswordMandatorio), false);

            persona.Usuario.Perfil = _seguridad.LeerPerfil(persona.Usuario.Perfil.Id);

            persona.Usuario.Perfil.Permisos = _seguridad.LeerPermisos(persona.Usuario.Perfil);

            if (persona.Usuario.Perfil.Permisos == null || persona.Usuario.Perfil.Permisos.Count == 0)//TODO: IMPLEMENTAR MENSAJE PARA USUARIO SIN PERMISOS
                throw new ExcepcionNegocio(_mensaje.ObtenerMensaje(MensajesPermitidos.PasswordMandatorio), false);

            persona.Usuario.Perfil.MenuPermitidos = ArmarEstructuraDeMenu(persona.Usuario.Id, idLenguaje);

            persona.DatosPersonales = _comun.LeerInformacionPersonal(persona.DatosPersonales.Id, idLenguaje);
            persona.DatosDomiciliarios = _comun.LeerInformacionDomiciliaria(persona.DatosDomiciliarios.Id);
            
            return persona;
        }

        private List<Menu> ArmarEstructuraDeMenu(int idUsuario, int idLenguaje)
        {
            var menuesSinProcesar = _seguridad.LeerMenusDeUsuario(idUsuario, idLenguaje);

            var menuPadres = menuesSinProcesar.Where(menu => menu.Padre == 0).ToList();

            menuPadres.ForEach(menuPadre => menuPadre.Items.AddRange(menuesSinProcesar.Where(menu => menu.Padre == menuPadre.Id)));

            return menuPadres;
        }


        public List<Ambito> LeerAmbitos(int idLenguaje)
        {
            return _cache.ObtenerLista<Ambito>() ?? _cache.SetearLista(_seguridad.LeerAmbitos(idLenguaje));
        }


        public List<Perfil> BuscarPerfiles(Perfil perfil, int idLenguaje)
        {
            var perfiles = _seguridad.BuscarPerfiles(perfil);
            var ambitos = LeerAmbitos(idLenguaje);


            return perfiles.Select(perf =>
            {
                perf.Ambito =
                    ambitos.Single(ambito => ambito.IdAmbito == perf.Ambito.IdAmbito);
                return perf;
            }).ToList();
        }


        public void GuardarPerfil(Perfil perfil)
        {
            //TODO: antes de seguir creando mensajes, verificar que esto funcione bien
            if(perfil.Ambito == null)
                throw new ExcepcionNegocio(_mensaje.ObtenerMensaje(MensajesPermitidos.UsuarioMandatorio), false);

            if(String.IsNullOrEmpty(perfil.Codigo))
                throw new ExcepcionNegocio(_mensaje.ObtenerMensaje(MensajesPermitidos.UsuarioMandatorio), false);

            if (String.IsNullOrEmpty(perfil.Descripcion))
                throw new ExcepcionNegocio(_mensaje.ObtenerMensaje(MensajesPermitidos.UsuarioMandatorio), false);

            if (String.IsNullOrEmpty(perfil.Nombre))
                throw new ExcepcionNegocio(_mensaje.ObtenerMensaje(MensajesPermitidos.UsuarioMandatorio), false);

            if (perfil.Permisos == null || perfil.Permisos.Count == 0)
                throw new ExcepcionNegocio(_mensaje.ObtenerMensaje(MensajesPermitidos.UsuarioMandatorio), false);

            _seguridad.GuardarPerfil(perfil);
        }

        public List<Permiso> LeerPermisos(int idLenguaje)
        {
            return _cache.ObtenerLista<Permiso>() ?? _cache.SetearLista(_seguridad.LeerPermisos(idLenguaje));
        }


        public Perfil LeerPerfil(int idPerfil)
        {
            var perfil = _seguridad.LeerPerfil(idPerfil);
            perfil.Permisos = _seguridad.LeerPermisos(perfil);

            return perfil;
        }

        public List<Persona> BuscarPersonas(Persona persona)
        {
            throw new NotImplementedException("Implementar si es necesario");
        }

        public List<Persona> BuscarPersonas(Persona persona, int idLenguaje)
        {
            var personas = _seguridad.BuscarPersonas(persona);
            var perfiles = _seguridad.BuscarPerfiles(new Perfil());
            var ambitos = LeerAmbitos(idLenguaje);

            foreach (var per in personas)
            {
                per.Usuario = _seguridad.LeerUsuario(per.Usuario.Id);
                foreach (var ambito in ambitos.Where(ambito => per.Ambito.IdAmbito == ambito.IdAmbito))
                    per.Ambito = ambito;

                foreach (var perfil in perfiles.Where(perfil => perfil.Id == per.Usuario.Perfil.Id))
                    per.Usuario.Perfil = perfil;
            }


            return personas;
        }

        public List<Perfil> LeerPerfiles()
        {
            return _seguridad.BuscarPerfiles(new Perfil());
        }

        public Persona LeerPersona(int idPersona, int idLenguaje)
        {
            var persona = _seguridad.LeerPersona(idPersona);

            persona.DatosPersonales = _comun.LeerInformacionPersonal(persona.DatosPersonales.Id, idLenguaje);
            persona.DatosDomiciliarios = _comun.LeerInformacionDomiciliaria(persona.DatosDomiciliarios.Id);

            if (persona.GetType() == typeof(Cliente))
                ((Cliente) persona).DatosDeEmpresa =
                    _comun.LeerInformacionDeEmpresa(((Cliente) persona).DatosDeEmpresa.Id);

            return persona;
        }




        public Persona GuardarPersona(Persona persona)
        {
            return _seguridad.GuardarPersona(persona);
        }

        #region ISeguridad Members


        

        #endregion


        [Obsolete("Usar LeerPersona(int idPersona, int idLenguaje)")]
        public Persona LeerPersona(int idPersona)
        {
            throw new NotImplementedException();
        }
    }
}